package com.jkt.rms.businessservice.impl;

import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Property;

import com.jkt.rms.adapter.EmailAdaptor;
import com.jkt.rms.business.AppRole;
import com.jkt.rms.business.Authorities;
import com.jkt.rms.business.Users;
import com.jkt.rms.business.Vendor;
import com.jkt.rms.businessservice.UserBusinessService;
import com.jkt.rms.cache.RMSCache;
import com.jkt.rms.commons.configuration.MessageSourceImpl;
import com.jkt.rms.commons.utils.EqualityUtils;
import com.jkt.rms.commons.utils.RMSException;
import com.jkt.rms.commons.utils.SecurityHelper;
import com.jkt.rms.commons.utils.ServiceLocator;
import com.jkt.rms.constants.IConstants;
import com.jkt.rms.dataservice.UserDataService;
import com.jkt.rms.vo.UsersVO;

public class UserBusinessServiceImpl implements UserBusinessService {

	private static final Logger LOG = Logger.getLogger(UserBusinessServiceImpl.class);
	private UserDataService userDataService;
	
	private static MessageSourceImpl messagesourceimpl;
	private String message="";
	private RMSCache cache;
	public void setUserDataService(UserDataService userDataService) {
		this.userDataService = userDataService;
	}

	public AppRole validateUser(String empCode, String password,HttpServletRequest request) {
		HttpSession userSession = request.getSession(true);
		Map<String, String> model = new HashMap<String, String>();
		AppRole appRole =  userDataService.validateUser(empCode, password);
		if(appRole  == null){
				model.put("Error", "Either User Name or Password is incorrect!");
			}
			else{
				UsersVO userDataVO = new UsersVO();
				userDataVO.setUsername(appRole.getLoginID());
				userDataVO.setPassword(appRole.getPassword());
				userSession.setAttribute("USERDATA",userDataVO );
		}
		return appRole;
	}
	
	public boolean updateUser(UsersVO userData) {
		boolean status = false;
		Users userDB  = getUserData(userData);
		if(userDB != null){
			userDB.setPassword(SecurityHelper.encrypt(userData.getNewPassword()));
			try {
				userDataService.updateUser(userDB);
				status = true;
			} catch (RMSException e) {
				status = false;
				LOG.error("Exception Occurs in updateUser:" + e.getCause());
			}
		}
		return status;
	}
	
	public Users getUserData(UsersVO userData) {
		Users user = userDataService.getUserData(userData.getUsername().trim());
		return user;
		
	}
	/**
	 * This method does the functionality to send the mail to user 
	 * who makes the request to forgot the password.
	 * @param user
	 * @param subject
	 * @param message
	 * @return boolean
	 * @throws RMSExcetion
	 */
	 @Override
	   public boolean pwdEmailService(Users user) throws RMSException {
		   	messagesourceimpl = ServiceLocator.getServiceLocator().locate("messageSourceImpl");
		   	String subject=messagesourceimpl.getMessage("pwd.mail.subject");
			String emailFooter=messagesourceimpl.getMessage("email.footer.message");
			String bodyUsermsg=messagesourceimpl.getMessage("pwd.mail.body.usermsg");
			String bodyPwdmsg=messagesourceimpl.getMessage("pwd.mail.body.pwdmsg");
			String emailID=user.getEmail();
			StringBuffer sbMessage = new StringBuffer();
			sbMessage.append("Dear "+user.getFirstName()+", \n\n");
			sbMessage.append(bodyUsermsg+user.getUsername()+"\n\n");
			sbMessage.append(bodyPwdmsg+user.getPassword()+"\n\n");
			sbMessage.append(emailFooter);
			String txtMessage = sbMessage.toString();   
			boolean status=EmailAdaptor.sendEmail(emailID,subject,txtMessage);
			return status;
	   }
	 
	 @Override
	public boolean saveUsers(UsersVO userVO) throws RMSException {
		 boolean status = false;
		 
		 Users user =  getUserData(userVO);
		 if(user == null) {
			 if(isEmailExist(userVO)){
				 message = IConstants.EXISTS;
				 return status;
			 }
			 final Users users = new Users();
			 final Authorities authObj =  new Authorities();
			 final Authorities authObj1 =  new Authorities();
			 List<Authorities> listAuthorities = new ArrayList<Authorities>();
			 authObj.setUsername(userVO.getRoleName());
			 authObj.setAuthority(userVO.getRoleName());
			 listAuthorities.add(authObj);
			 authObj1.setUsername(userVO.getUsername());
			 authObj1.setAuthority(IConstants.ROLE_NAME);
			 listAuthorities.add(authObj1);
			 EqualityUtils.copyProperties(users, userVO);
			 users.setListAuthorities(listAuthorities);
			 users.setEnabled('1');
			 users.setUpdatedDate(new Timestamp(System.currentTimeMillis()));
			 users.setUpdatedBy("Admin");//TO DO CHANGE TASK
			 userDataService.saveUsers(users);
			 getCache();
			 cache.refersh(RMSCache.USERCACHE);
			 status = true;
		 } 
		 return status;
	}
	 public boolean isEmailExist(UsersVO userVO) throws RMSException{
		 boolean status = false;
		 RMSCache cache = ServiceLocator.getServiceLocator().locate("cacheService");
		List<Users> listUsers =  cache.getAllActiveUsers();
		for (Users users : listUsers) {
			if(EqualityUtils.isNotNull(users.getEmail()) &&  users.getEmail().equalsIgnoreCase(userVO.getEmail().trim())){
				status = true;
				break;
			}
		}
		 return status;
	 }

	public String getMessage() {
		return message;
	}

	public List<UsersVO> searchUser(UsersVO userVO)throws RMSException { 
		DetachedCriteria criteria = DetachedCriteria.forClass(Users.class);
		if (userVO != null) {
			if (EqualityUtils.isNotNull(userVO.getSrchFirstName())) {
				criteria.add(Expression.like(Users.PROP_FIRSTNAME, userVO.getSrchFirstName().trim() + "%"));
			}
			if (EqualityUtils.isNotNull(userVO.getSrchLastName())) {
				criteria.add(
						Expression.like(Users.PROP_LASTNAME, userVO.getSrchLastName().trim() + "%"));
			}
			if (EqualityUtils.isNotNull(userVO.getSrchUserName())) {
				criteria.add(Expression.like(Users.PROP_USERNAME, userVO.getSrchUserName().trim() + "%"));
			}
			if (EqualityUtils.isNotNull(userVO.getSrchRoleName())) {
				criteria.createCriteria("listAuthorities")
				.add(Expression.like(Authorities.PROP_AUTHORITY, userVO.getSrchRoleName().trim() + "%"));
						
				
			}
		}
		List<Users> list = userDataService.findByCriteria(criteria);
		return getUserVOList(list);
		
	}

	
	private UsersVO getUsersVO(Users usersData) throws RMSException {
		final UsersVO usersVO = new UsersVO();
		List<Authorities> listAuthor =  usersData.getListAuthorities();
		EqualityUtils.copyProperties(usersVO, usersData);
		if(usersData.getEnabled() ==IConstants.ACTIVE){
			usersVO.setEnabled('Y');	
		}else {
			usersVO.setEnabled('N');	
		}
		usersVO.setListUserRoles(listAuthor);
		return usersVO;
	}

	private List<UsersVO> getUserVOList(List<Users> usersList) {
		final List<UsersVO> usersVOList = new ArrayList<UsersVO>();
		for (Users user : usersList) {
			try {
				usersVOList.add(getUsersVO(user));
			} catch (RMSException e) {
				LOG.error(" Exception occured in search", e.getCause());
			}
		}
		return usersVOList;
	}
	
	@Override
	public List<UsersVO> findAllUsers() throws RMSException {
		List<Users> listAllUser = userDataService.findAll();
		return getUserVOList(listAllUser);
	}
	
	@Override
	public UsersVO getUserDataByName(String userName) throws RMSException { 
		 getCache();
		Users user =cache.getUser(userName.trim());
		UsersVO userVO =  getUsersVO(user);
		if(userVO.getEnabled() == 'Y') {
			userVO.setEnabled(IConstants.ACTIVE);
		}else {
			userVO.setEnabled(IConstants.INACTIVE);
		}
		return userVO;
	}
	
	@Override
	public boolean updateUserData(UsersVO usersVO)   {
		boolean status = false;
		Users user = userDataService.getUserData(usersVO.getUsername().trim());
		usersVO.setPassword(user.getPassword());
		List<Authorities> listRoleDB = user.getListAuthorities();
		if(listRoleDB != null) {
		for (Authorities authorities : listRoleDB) {
			if(authorities.getAuthority().equals( IConstants.ROLE_NAME)){
				continue;
			}else {
				authorities.setAuthority(usersVO.getRoleName());
			}
		}
	}
		try {
			
			EqualityUtils.copyProperties(user, usersVO);
			user.setUpdatedDate(new Timestamp(System.currentTimeMillis()));
			
		} catch (RMSException e) {
			LOG.debug("Exception Occurs in Copy Properties ", e.getCause());
		}
		try {
			userDataService.updateUserData(user);
			getCache();
			cache.refersh(RMSCache.USERCACHE);
			status = true;
		} catch (RMSException e) {
			status = false;
		}
		return status;
	}
	private RMSCache getCache() {
		cache = ServiceLocator.getServiceLocator().locate("cacheService");
		return cache;
	}
	 
}
